﻿using System.ComponentModel;
using System.IO.IsolatedStorage;

using Microsoft.Practices.Composite.Events;

using Matchingo.Common.Constants;
using Matchingo.Common.Types.Types;
using Matchingo.Common.Types.Events;
using Matchingo.Common.Types.Interfaces;

namespace Matchingo.Models.SettingsProvider
{
    public class GameSettingsProvider : IGameSettingsProvider
    {
        #region ========== Private Constants ==========

        private const int GAME_SETTINGS_CARD_COUNT = CommonConstants.GAME_SETTINGS_DEFAULT_CARDCOUNT;
        private const bool GAME_SETTINGS_AI_GAME = CommonConstants.GAME_SETTINGS_DEFAULT_AIGAME;        
        private const string GAME_SETTINGS_PLAYER_NAME = CommonConstants.GAME_SETTINGS_DEFAULT_PLAYERNAME;
		private const double GAME_SETTINGS_SOUND_VOLUME = CommonConstants.GAME_SETTINGS_DEFAULT_SOUNDVOLUME;
		private const string GAME_SETTINGS_CARD_SET_NAME = CommonConstants.GAME_SETTINGS_DEFAULT_CARDSETNAME;
		private const string GAME_SETTINGS_BACKGROUND_SET_NAME = CommonConstants.GAME_SETTINGS_DEFAULT_BACKGROUNDSETNAME;

        private const string AI_GAME_FIELD_NAME = "AIGame";
        private const string CARD_COUNT_FIELD_NAME = "CardCount";
        private const string PLAYER_NAME_FIELD_NAME = "PlayerName";
		private const string SOUND_VOLUME_FIELD_NAME = "SoundVolume";
		private const string CARD_SET_NAME_FIELD_NAME = "CardSetName";
		private const string BACKGROUND_SET_NAME_FIELD_NAME = "BackgroundSetName";

        #endregion

        #region ========== Private Members ==========

        private readonly IEventAggregator EventAggregator;

        #endregion

        #region ========== Public Properties ==========

        private MatchGameSettings _gameSettings;
        public MatchGameSettings GameSettings 
        {
            get { return _gameSettings; }
            private set
            {
                _gameSettings = value;
                NotifyPropertyChanged("GameSettings");
            }
        }

        #endregion

        #region ========== Constructors ==========

        public GameSettingsProvider(IEventAggregator eventAggregator)
        {
            GameSettings = new MatchGameSettings()
            {
                AIGame = GAME_SETTINGS_AI_GAME,
                CardCount = GAME_SETTINGS_CARD_COUNT,
                PlayerName = GAME_SETTINGS_PLAYER_NAME
            };

            EventAggregator = eventAggregator;
        }

        #endregion

        #region ========== Public Methods ==========

        public void Initialize()
        {
            LoadSettings();            
        }

        public void SaveSettings()
        {
            AddValueToApplicationSettings(AI_GAME_FIELD_NAME, GameSettings.AIGame);
            AddValueToApplicationSettings(CARD_COUNT_FIELD_NAME, GameSettings.CardCount);
            AddValueToApplicationSettings(PLAYER_NAME_FIELD_NAME, GameSettings.PlayerName);
			AddValueToApplicationSettings(SOUND_VOLUME_FIELD_NAME, GameSettings.SoundVolume);
			AddValueToApplicationSettings(BACKGROUND_SET_NAME_FIELD_NAME, GameSettings.BackgroundSetName);
			AddValueToApplicationSettings(CARD_SET_NAME_FIELD_NAME, GameSettings.CardSetName);

            LoadSettings();
        }

        #endregion

        #region ========== Private Methods ==========

        private void LoadSettings()
        {
            // load the settings from the application settings, if they come back null then
            // use the defaults
            MatchGameSettings gameSettings = new MatchGameSettings();
            gameSettings.AIGame = (GetValueFromApplicationSettings(AI_GAME_FIELD_NAME) == null) ?
                GAME_SETTINGS_AI_GAME : bool.Parse(GetValueFromApplicationSettings(AI_GAME_FIELD_NAME));
            gameSettings.CardCount = (GetValueFromApplicationSettings(CARD_COUNT_FIELD_NAME) == null) ?
                GAME_SETTINGS_CARD_COUNT : int.Parse(GetValueFromApplicationSettings(CARD_COUNT_FIELD_NAME));
            gameSettings.SoundVolume = (GetValueFromApplicationSettings(SOUND_VOLUME_FIELD_NAME) == null) ?
                GAME_SETTINGS_SOUND_VOLUME : double.Parse(GetValueFromApplicationSettings(SOUND_VOLUME_FIELD_NAME));
            gameSettings.PlayerName = GetValueFromApplicationSettings(PLAYER_NAME_FIELD_NAME) ?? GAME_SETTINGS_PLAYER_NAME;
            gameSettings.BackgroundSetName = GetValueFromApplicationSettings(BACKGROUND_SET_NAME_FIELD_NAME) ?? GAME_SETTINGS_BACKGROUND_SET_NAME;
            gameSettings.CardSetName = GetValueFromApplicationSettings(CARD_SET_NAME_FIELD_NAME) ?? GAME_SETTINGS_CARD_SET_NAME;

            // save back the settings so that they have settings for next time
            GameSettings = gameSettings;

            EventAggregator.GetEvent<SettingsChangedEvent>().Publish(GameSettings);
        }

        private static string GetValueFromApplicationSettings(string key)
        {
            IsolatedStorageSettings userSettings = IsolatedStorageSettings.ApplicationSettings;
            if (!userSettings.Contains(key))
            {
                return null;
            }
            if (userSettings[key] != null)
            {
                return userSettings[key].ToString();
            }

            return null;
        }

        private static void AddValueToApplicationSettings(string key, bool value)
        {
            AddValueToApplicationSettings(key, value.ToString());
        }

        private static void AddValueToApplicationSettings(string key, int value)
        {
            AddValueToApplicationSettings(key, value.ToString());
        }

		private static void AddValueToApplicationSettings(string key, double value)
		{
			AddValueToApplicationSettings(key, value.ToString());
		}

        private static void AddValueToApplicationSettings(string key, string value)
        {
            IsolatedStorageSettings userSettings = null;
            userSettings = IsolatedStorageSettings.ApplicationSettings;
            userSettings[key] = value;
        }

        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged == null)
                return;

            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion

        #region ========== Public Events ==========

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}
